package com.lzw.DailyAudit.service.dateAggregation_02.DailyAudit.service.issueReports_04;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.excel.EasyExcel;
import com.hooya.fa.eu.biz.DailyAudit.entity.dto.StockListDTO;
import com.hooya.fa.eu.biz.DailyAudit.entity.dto.StockListExcelDTO;
import com.hooya.fa.eu.biz.DailyAudit.mapper.*;
import com.hooya.fa.eu.biz.DailyAudit.service.dateAggregation_02.CommonService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Slf4j
public class StockList {

    @Autowired
    private DailyStkOrigDataCollectMapper dailyStkOrigDataCollectMapper;

    @Autowired
    private DailyMetaExchangePlMapper dailyMetaExchangePlMapper;

    @Autowired
    private DailyTempKcjlDailyMapper dailyTempKcjlDailyMapper;

    @Autowired
    private DailyMetaWarehouseMapper dailyMetaWarehouseMapper;

    @Autowired
    private CommonService commonService;

    /**
     * 主方法
     */
    public void stockList(String currentDate) {
        try {

            log.info("StockList开始执行");

            // 计算结束日期
            String[] split = currentDate.split("-");
            if (split.length != 3) {
                log.error("日期格式有误！");
                return;
            }
            String year = split[0];
            String month = split[1];
            String day = split[2];

            List<StockListDTO> origData = unitData(currentDate);

            Map<String, List<StockListDTO>> stringListMap = dealPrice(origData);
            List<StockListDTO> priceData = stringListMap.get("priceData");
            List<StockListDTO> noPriceData = stringListMap.get("noPriceData");

            if (!noPriceData.isEmpty()) {
                log.error("有数据为空");
                throw new RuntimeException("有数据为空");
            }

            List<StockListDTO> stockData = dealStockQty(priceData, currentDate);

            List<StockListDTO> whNameData = dealWarehouseName(stockData);
            List<StockListDTO> inoutData = dealDirection(whNameData);
            List<StockListDTO> lastData = dealTypeQty(inoutData);
            List<StockListDTO> kcData = getKc(currentDate);

            List<StockListDTO> AllData = new ArrayList<>(lastData);
            AllData.addAll(kcData);

            // 创建输出目录
            String dir = "./stocklist/" + year + "/" + month + "/" + day;
            commonService.createDirectories(dir);

            // 按 belongs 分组并导出到 Excel
            exportDataToExcel(dir, AllData, year, month, day);

            log.info("StockList执行成功");
        } catch (Exception e) {
            log.error("处理StockList数据时发生错误", e);
            throw new RuntimeException("处理StockList数据时发生错误", e);
        }
    }

    private List<StockListDTO> getKc(String currentDate) {
        String[] belongs = {"costway-fr", "costway-it", "costway-de", "costway-pl"};
        List<StockListDTO> result = new ArrayList<>();
        for (String belong : belongs) {
            List<String> order = dailyStkOrigDataCollectMapper.getSkuByBelong(belong, currentDate);
            List<StockListDTO> kc = dailyStkOrigDataCollectMapper.getDataByBelong(currentDate, belong);
            kc.forEach(f -> f.setDate(currentDate));
            List<StockListDTO> newkc = kc.stream().filter(f -> !order.contains(f.getSku())).collect(Collectors.toList());
            result.addAll(newkc);
        }
        return result;
    }

    /**
     * 整合所有原始数据
     */
    public List<StockListDTO> unitData(String currentDate) {
        String beforeDate = commonService.getPrevDate(currentDate);
        List<StockListDTO> b2bData = dailyStkOrigDataCollectMapper.getB2bData(currentDate);
        b2bData.forEach(f -> f.setExchangedate(beforeDate));

        List<StockListDTO> b2cData = dailyStkOrigDataCollectMapper.getB2cData(currentDate);
        b2cData.forEach(f -> f.setExchangedate(commonService.getPrevDate(f.getInvoiceDate())));

        List<StockListDTO> bsData = dailyStkOrigDataCollectMapper.getBsData(currentDate);
        bsData.forEach(f -> f.setExchangedate(commonService.getPrevDate(f.getInOutDate())));

        List<StockListDTO> cgData = dailyStkOrigDataCollectMapper.getCgData(currentDate);
        cgData.forEach(f -> f.setExchangedate(commonService.getPrevDate(f.getInvoiceDate())));

        List<StockListDTO> thData = dailyStkOrigDataCollectMapper.getThData(currentDate);
        thData.forEach(f -> f.setExchangedate(commonService.getPrevDate(f.getInvoiceDate())));

        List<StockListDTO> zyData = dailyStkOrigDataCollectMapper.getZyData(currentDate);
        zyData.forEach(f -> f.setExchangedate(commonService.getPrevDate(f.getInvoiceDate())));

        List<StockListDTO> origData = new ArrayList<>();
        origData.addAll(b2bData);
        origData.addAll(b2cData);
        origData.addAll(bsData);
        origData.addAll(cgData);
        origData.addAll(thData);
        origData.addAll(zyData);

        origData.forEach(f -> {
            f.setDate(currentDate);
            f.setInvoiceNumber(f.getInvoiceno());
        });

        return origData;
    }

    /**
     * 处理价格和汇率
     */
    public Map<String, List<StockListDTO>> dealPrice(List<StockListDTO> data) {
        Map<String, List<StockListDTO>> result = new HashMap<>();

        // 获取汇率数据
        List<StockListDTO> exchangeList = dailyMetaExchangePlMapper.getDataForStockList();

        List<StockListDTO> noPriceData = data.stream()
                .filter(dto -> dto.getPrice() == null)
                .collect(Collectors.toList());

        data.forEach(dto -> {
            if (dto.getPrice() != null && dto.getQty() != null) {
                dto.setTotalcost(dto.getPrice() * dto.getQty());
            } else {
                dto.setTotalcost(0.0);
            }
        });

        List<StockListDTO> eurData = data.stream().filter(f -> "EUR".equals(f.getCurrency())).collect(Collectors.toList());
        if (!eurData.isEmpty()) {
            Map<String, List<StockListDTO>> descriptionDataMap = exchangeList.stream().collect(Collectors.groupingBy(StockListDTO::getRatedate));
            List<StockListDTO> withDescription = new ArrayList<>();
            for (StockListDTO mainItem : eurData) {
                String key = mainItem.getExchangedate();
                if (descriptionDataMap.containsKey(key)) {
                    List<StockListDTO> StockListDTOS = descriptionDataMap.get(key);
                    StockListDTOS.forEach(f -> {
                        StockListDTO newItem = new StockListDTO();
                        BeanUtil.copyProperties(mainItem, newItem);
                        newItem.setEurplnrate(f.getEurplnrate());
                        newItem.setUsdplnrate(f.getUsdplnrate());
                        newItem.setUsdeurrate(f.getUsdeurrate());
                        newItem.setExistflag(f.getExistflag());
                        newItem.setUnitPricePln((newItem.getPrice() == null ? 0.0 : newItem.getPrice()) * (newItem.getEurplnrate() == null ? 0.0 : newItem.getEurplnrate()));
                        newItem.setCurrencyRate(f.getEurplnrate());
                        newItem.setUnitPriceEur(newItem.getPrice());
                        withDescription.add(newItem);
                    });
                } else {
                    withDescription.add(mainItem);
                }
            }
            eurData = withDescription;
        }

        List<StockListDTO> usdData = data.stream().filter(f -> "USD".equals(f.getCurrency())).collect(Collectors.toList());
        if (!usdData.isEmpty()) {
            Map<String, List<StockListDTO>> descriptionDataMap = exchangeList.stream().collect(Collectors.groupingBy(StockListDTO::getRatedate));
            List<StockListDTO> withDescription = new ArrayList<>();
            for (StockListDTO mainItem : usdData) {
                String key = mainItem.getExchangedate();
                if (descriptionDataMap.containsKey(key)) {
                    List<StockListDTO> StockListDTOS = descriptionDataMap.get(key);
                    StockListDTOS.forEach(f -> {
                        StockListDTO newItem = new StockListDTO();
                        BeanUtil.copyProperties(mainItem, newItem);
                        newItem.setEurplnrate(f.getEurplnrate());
                        newItem.setUsdplnrate(f.getUsdplnrate());
                        newItem.setUsdeurrate(f.getUsdeurrate());
                        newItem.setExistflag(f.getExistflag());
                        newItem.setUnitPricePln((newItem.getPrice() == null ? 0.0 : newItem.getPrice()) * (newItem.getUsdplnrate() == null ? 0.0 : newItem.getUsdplnrate()));
                        newItem.setCurrencyRate(newItem.getUsdplnrate());
                        newItem.setUnitPriceUSD(newItem.getPrice());
                        withDescription.add(newItem);
                    });
                } else {
                    withDescription.add(mainItem);
                }
            }
            usdData = withDescription;
        }

        List<StockListDTO> plnData = data.stream().filter(f -> "PLN".equals(f.getCurrency())).collect(Collectors.toList());
        if (!plnData.isEmpty()) {
            plnData.forEach(f -> f.setUnitPricePln(f.getPrice()));
        }

        List<StockListDTO> addExchangeData = new ArrayList<>(eurData);
        addExchangeData.addAll(usdData);
        addExchangeData.addAll(plnData);

        result.put("priceData", addExchangeData);
        result.put("noPriceData", noPriceData);
        return result;
    }

    /**
     * 处理库存数量
     */
    public List<StockListDTO> dealStockQty(List<StockListDTO> data, String currentDate) {
        String preMonthEnd = commonService.getPrevDate(currentDate);

        List<StockListDTO> beginQty = dailyTempKcjlDailyMapper.getBeginQty_StockList(preMonthEnd);
        List<StockListDTO> endQty = dailyTempKcjlDailyMapper.getEndQty_StockList(currentDate);

        Map<String, List<StockListDTO>> beginQtyDataMap = beginQty.stream().collect(Collectors.groupingBy(f -> f.getSku() + f.getWhId() + f.getBelongs()));
        List<StockListDTO> addBeginStock = new ArrayList<>();
        for (StockListDTO mainItem : data) {
            String key = mainItem.getSku() + mainItem.getWhId() + mainItem.getBelongs();
            if (beginQtyDataMap.containsKey(key)) {
                List<StockListDTO> StockListDTOS = beginQtyDataMap.get(key);
                StockListDTOS.forEach(f -> {
                    StockListDTO newItem = new StockListDTO();
                    BeanUtil.copyProperties(mainItem, newItem);
                    newItem.setBeginqty(f.getBeginqty());
                    addBeginStock.add(newItem);
                });
            } else {
                addBeginStock.add(mainItem);
            }
        }

        Map<String, List<StockListDTO>> endQtyDataMap = endQty.stream().collect(Collectors.groupingBy(f -> f.getSku() + f.getWhId() + f.getBelongs()));
        List<StockListDTO> addEndStock = new ArrayList<>();
        for (StockListDTO mainItem : addBeginStock) {
            String key = mainItem.getSku() + mainItem.getWhId() + mainItem.getBelongs();
            if (endQtyDataMap.containsKey(key)) {
                List<StockListDTO> StockListDTOS = endQtyDataMap.get(key);
                StockListDTOS.forEach(f -> {
                    StockListDTO newItem = new StockListDTO();
                    BeanUtil.copyProperties(mainItem, newItem);
                    newItem.setEndqty(f.getEndqty());
                    addEndStock.add(newItem);
                });
            } else {
                addEndStock.add(mainItem);
            }
        }

        addEndStock.forEach(f -> {
            f.setStockBeginOfMonth(f.getBeginqty());
            f.setStockEndOfMonth(f.getEndqty());
        });

        return addEndStock;
    }

    /**
     * 处理仓库名称
     */
    public List<StockListDTO> dealWarehouseName(List<StockListDTO> data) {
        List<StockListDTO> whNameData = dailyMetaWarehouseMapper.getData();

        Map<String, List<StockListDTO>> descriptionDataMap = whNameData.stream().collect(Collectors.groupingBy(StockListDTO::getWhId));
        List<StockListDTO> withDescription = new ArrayList<>();
        for (StockListDTO mainItem : data) {
            String key = mainItem.getWhId();
            if (descriptionDataMap.containsKey(key)) {
                List<StockListDTO> StockListDTOS = descriptionDataMap.get(key);
                StockListDTOS.forEach(f -> {
                    StockListDTO newItem = new StockListDTO();
                    BeanUtil.copyProperties(mainItem, newItem);
                    newItem.setWhName(f.getWhName());
                    withDescription.add(newItem);
                });
            } else {
                withDescription.add(mainItem);
            }
        }

        return withDescription;
    }

    /**
     * 处理出入库方向
     */
    public List<StockListDTO> dealDirection(List<StockListDTO> data) {
        // TODO -- 可能会出现问题 由于数据列的关系--py中独有的内容
        List<StockListDTO> inData = data.stream().filter(f -> "in".equals(f.getDirection())).collect(Collectors.toList());
        inData.forEach(f -> {
            f.setInboundQty(f.getQty());
            f.setInCostNet(f.getTotalcost());
            f.setInPriceNetEur("EUR".equals(f.getCurrency()) ? f.getUnitPriceEur() : null);
            f.setInPriceNetUsd("USD".equals(f.getCurrency()) ? f.getUnitPriceUSD() : null);
            f.setInPriceNetPln("PLN".equals(f.getCurrency()) ? f.getUnitPricePln() : null);
        });

        List<StockListDTO> outData = data.stream().filter(f -> "out".equals(f.getDirection())).collect(Collectors.toList());
        outData.forEach(f -> {
            f.setOutboundQty(f.getQty());
            f.setOutRevenueNet(f.getTotalcost());
            f.setOutPriceNetEur("EUR".equals(f.getCurrency()) ? f.getUnitPriceEur() : null);
            f.setOutPriceNetUsd("USD".equals(f.getCurrency()) ? f.getUnitPriceUSD() : null);
            f.setOutPriceNetPln("PLN".equals(f.getCurrency()) ? f.getUnitPricePln() : null);
        });

        List<StockListDTO> inoutData = new ArrayList<>(inData);
        inoutData.addAll(outData);
        inoutData.forEach(f -> {
            f.setUnitPriceEur("EUR".equals(f.getCurrency()) ? f.getUnitPriceEur() : null);
            f.setCurrencyRate("EUR".equals(f.getCurrency()) ? f.getCurrencyRate() : null);
        });

        return inoutData;
    }

    /**
     * 处理类型和数量
     */
    public List<StockListDTO> dealTypeQty(List<StockListDTO> data) {
        return data.stream().peek(item -> {

            String type = item.getType();
            Integer qty = item.getQty();

            // 处理报损和退货
            if ("报损".equals(type) || "退货".equals(type)) {
                item.setInventoryLossIncome(qty);
            }

            // 处理转运
            if ("转运".equals(type)) {
                item.setTransferBetweenWarehouses(qty);
                // 转运类型不需要发票日期
                item.setInvoiceDate(null);
            }

            // 处理B2C
            if ("B2C".equals(type)) {
                item.setB2c(qty);
            }

            // 处理B2B
            if ("B2B".equals(type)) {
                item.setB2b(qty);
            }

            // 处理退货类型不需要发票日期
            if ("退货".equals(type)) {
                item.setInvoiceDate(null);
            }

            // java中不需要转null值，所以这里也不需要回转为null
            // 处理转运类型的bor_inv
            if (!"转运".equals(type)) {
                item.setBorInv(null);
            }

        }).collect(Collectors.toList());
    }

    /**
     * 按 belongs 分组并导出到 Excel
     *
     * @param data  数据列表
     * @param year  年份
     * @param month 月份
     */
    private void exportDataToExcel(String dir, List<StockListDTO> data, String year, String month, String day) {
        try {
            // 按 belongs 分组
            Map<String, List<StockListDTO>> groupedData = data.stream()
                    .collect(Collectors.groupingBy(StockListDTO::getBelongs));

            for (Map.Entry<String, List<StockListDTO>> entry : groupedData.entrySet()) {
                String belong = entry.getKey();
                List<StockListDTO> groupData = entry.getValue();

                // 创建文件路径
                String fileDir = dir + "/" + belong + "-" + year + month + day;
                String fileName = String.format(fileDir + ".xlsx");

                // 处理空值数据
                handleData(groupData);

                // 使用EasyExcel写入文件
                writeExcelWithEasyExcel("stockList-" + year + "-" + month + "-" + day, groupData, fileName);
            }
            log.info("数据已成功导出到Excel文件");
        } catch (Exception e) {
            log.error("导出Excel文件失败", e);
            throw new RuntimeException("导出Excel文件失败", e);
        }
    }

    /**
     * 处理空值数据
     */
    private void handleData(List<StockListDTO> Data) {
        Data.forEach(f -> {
//            f.setDate(f.getDate() != null ? f.getDate() : "");
//            f.setWhId(f.getWhId() != null ? f.getWhId() : "");
//            f.setWhName(f.getWhName() != null ? f.getWhName() : "");
//            f.setSku(f.getSku() != null ? f.getSku() : "");
            f.setStockBeginOfMonth(f.getStockBeginOfMonth() != null ? f.getStockBeginOfMonth() : 0);
            f.setStockEndOfMonth(f.getStockEndOfMonth() != null ? f.getStockEndOfMonth() : 0);
//            f.setInOutDate(f.getInOutDate() != null ? f.getInOutDate() : "");
//            f.setInboundQty(f.getInboundQty() != null ? f.getInboundQty() : 0);
//            f.setInPriceNetEur(f.getInPriceNetEur() != null ? f.getInPriceNetEur() : 0.0);
//            f.setInPriceNetUsd(f.getInPriceNetUsd() != null ? f.getInPriceNetUsd() : 0.0);
//            f.setInPriceNetPln(f.getInPriceNetPln() != null ? f.getInPriceNetPln() : 0.0);
//            f.setInCostNet(f.getInCostNet() != null ? f.getInCostNet() : 0.0);
//            f.setOutboundQty(f.getOutboundQty() != null ? f.getOutboundQty() : 0);
//            f.setOutPriceNetEur(f.getOutPriceNetEur() != null ? f.getOutPriceNetEur() : 0.0);
//            f.setOutPriceNetUsd(f.getOutPriceNetUsd() != null ? f.getOutPriceNetUsd() : 0.0);
//            f.setOutPriceNetPln(f.getOutPriceNetPln() != null ? f.getOutPriceNetPln() : 0.0);
//            f.setOutRevenueNet(f.getOutRevenueNet() != null ? f.getOutRevenueNet() : 0.0);
//            f.setB2b(f.getB2b() != null ? f.getB2b() : 0);
//            f.setB2c(f.getB2c() != null ? f.getB2c() : 0);
//            f.setTransferBetweenWarehouses(f.getTransferBetweenWarehouses() != null ? f.getTransferBetweenWarehouses() : 0);
//            f.setBorInv(f.getBorInv() != null ? f.getBorInv() : "");
//            f.setInvoiceNumber(f.getInvoiceNumber() != null ? f.getInvoiceNumber() : "");
//            f.setInvoiceDate(f.getInvoiceDate() != null ? f.getInvoiceDate() : "");
//            f.setUnitPriceEur(f.getUnitPriceEur() != null ? f.getUnitPriceEur() : 0.0);
//            f.setCurrencyRate(f.getCurrencyRate() != null ? f.getCurrencyRate() : 0.0);
//            f.setUnitPricePln(f.getUnitPricePln() != null ? f.getUnitPricePln() : 0.0);
//            f.setSeller(f.getSeller() != null ? f.getSeller() : "");
//            f.setBuyer(f.getBuyer() != null ? f.getBuyer() : "");
//            f.setInventoryLossIncome(f.getInventoryLossIncome() != null ? f.getInventoryLossIncome() : 0);
//            f.setBelongs(f.getBelongs() != null ? f.getBelongs() : "");
        });
    }

    /**
     * 使用EasyExcel写入Excel文件
     *
     * @param sheetName sheet名称
     * @param groupData 分组数据
     * @param fileName  文件名
     */
    private void writeExcelWithEasyExcel(String sheetName, List<StockListDTO> groupData, String fileName) {
        try {
            // 将StockListDTO转换为StockListExcelDTO
            List<StockListExcelDTO> excelData = groupData.stream().map(item -> {
                StockListExcelDTO excelItem = new StockListExcelDTO();
                BeanUtil.copyProperties(item, excelItem);
                return excelItem;
            }).collect(Collectors.toList());

            // 使用EasyExcel写入文件
            EasyExcel.write(fileName, StockListExcelDTO.class)
                    .sheet(sheetName)
                    .doWrite(excelData);

            log.info("数据已成功写入Excel文件: {}", fileName);
        } catch (Exception e) {
            log.error("写入Excel文件失败: {}", fileName, e);
            throw new RuntimeException("写入Excel文件失败: " + fileName, e);
        }
    }

}